/* Copyright (c) 2010, mitsuhisa.net
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials provided
 *       with the distribution.
 *     * Neither the name of the misuhisa.net nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef HEAPOBJECT_HPP_
#define HEAPOBJECT_HPP_

#include <cstddef>
#include "MemoryManager.hpp"

namespace nyu {

class HeapObject {
public:
    void ref() {
        ++refcnt_;
    }

    void unref() {
        if (refcnt_ && --refcnt_ == 0) {
            MemoryManager::getInstance().addDestructQueue(this);
        }
    }

    size_t refcnt() const {
        return refcnt_;
    }

    bool isAlloced() const {
        return reinterpret_cast<long> (prev_) & 1;
    }

    void setAlloced(bool is_alloced) {
        prev_ = is_alloced ? reinterpret_cast<HeapObject*> (1) : 0;
    }

    static void* operator new(size_t size);

    class EachChildrenFunc {
    public:
        virtual ~EachChildrenFunc();
        virtual void operator()(HeapObject* p) const = 0;
    };

    virtual void eachChildren(const EachChildrenFunc& fn);

protected:
    HeapObject();
    virtual ~HeapObject();

    HeapObject(const HeapObject& rhs);
    HeapObject& operator=(const HeapObject& rhs);

private:
    size_t size_;
    size_t refcnt_;

    HeapObject* prev_;
    HeapObject* next_;

    size_t tmp_refcnt_;

    friend class MemoryManager;
};

}

#endif /* HEAPOBJECT_HPP_ */
